/**
 * 
 * 
 */
package com.cjfather.redis.steam.config;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

/**
 * @author: todd
 * @date:   2023年8月23日
 */

@Component
@Slf4j
public class RedisCacheUtil {
	
	public Gson gson = new GsonBuilder().create();
	
	@Resource(name = "redisObjFactory")
    public RedisTemplate redisTemplate;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @PostConstruct
    public void printConnectionInfo() {
        try {
            if (redisConnectionFactory instanceof JedisConnectionFactory) {
                JedisConnectionFactory jedisFactory = (JedisConnectionFactory) redisConnectionFactory;
                log.info("=== Jedis 连接信息 ===");
                log.info("主机: {}", jedisFactory.getHostName());
                log.info("端口: {}", jedisFactory.getPort());
                log.info("数据库: {}", jedisFactory.getDatabase());
                log.info("超时: {}ms", jedisFactory.getTimeout());
                log.info("使用SSL: {}", jedisFactory.isUseSsl());
                log.info("=========================");

            } else if (redisConnectionFactory instanceof LettuceConnectionFactory) {
                LettuceConnectionFactory lettuceFactory = (LettuceConnectionFactory) redisConnectionFactory;
                RedisStandaloneConfiguration config =
                        (RedisStandaloneConfiguration) lettuceFactory.getStandaloneConfiguration();

                log.info("=== Lettuce 连接信息 ===");
                log.info("主机: {}", config.getHostName());
                log.info("端口: {}", config.getPort());
                log.info("数据库: {}", config.getDatabase());
                log.info("=========================");
            }

            // 测试连接
            testConnection();

        } catch (Exception e) {
            log.error("获取 Redis 连接信息失败: {}", e.getMessage());
        }
    }

    private void testConnection() {
        try (RedisConnection connection = redisConnectionFactory.getConnection()) {
            String result = connection.ping();
            log.info("Redis 连接测试: {}", result);
        } catch (Exception e) {
            log.error("Redis 连接测试失败: {}", e.getMessage());
        }
    }

	/**
     * 缓存基本对象
     *
     * @param key   键
     * @param value 值
     */
    public <T> void setCacheObject(final String key, final T value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 缓存基本对象，含有效时间
     *
     * @param key     键
     * @param value   值
     * @param timeout 超时时间
     */
    public <T> void setCacheObject(final String key, final T value, final Long timeout, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
    }

    /**
     * 缓存List数据
     *
     * @param key      键
     * @param dataList 数据列表
     */
    public <T> long setCacheList(final String key, final List<T> dataList) {
        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
        return count == null ? 0 : count;
    }
    
    public <T> long setCacheList(final String key, final T data) {
        Long count = redisTemplate.opsForList().rightPush(key, data);
        return count == null ? 0 : count;
    }

    /**
     * 缓存Set数据
     *
     * @param key     键
     * @param dataSet 数据集合
     */
    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext()) {
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 缓存Map数据
     *
     * @param key     键
     * @param dataMap 数据键值对
     */
    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
        if (dataMap != null) {
            redisTemplate.opsForHash().putAll(key, dataMap);
        }
    }

    /**
     * 缓存Hash数据
     *
     * @param key     键
     * @param hashKey hash值
     * @param value   值
     */
    public <T> void setCacheMapValue(final String key, final String hashKey, final T value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 设置有效时间，以秒为单位
     *
     * @param key     键
     * @param timeout 超时时间
     * @return true=有效；false=失效
     */
    public boolean expire(final String key, final long timeout) {
        return expire(key, timeout, TimeUnit.SECONDS);
    }

    /**
     * 设置有效时间，自定义单位
     *
     * @param key     键
     * @param timeout 超时时间
     * @param unit    时间单位
     * @return true=有效；false=失效
     */
    public boolean expire(final String key, final Long timeout, final TimeUnit unit) {
        return redisTemplate.expire(key, timeout, unit);
    }

    /**
     * 删除单个对象
     *
     * @param key 键
     */
    public boolean deleteObject(final String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection 多个对象
     */
    public long deleteObjects(final Collection collection) {
        return redisTemplate.delete(collection);
    }

    /**
     * 删除Hash数据
     *
     * @param key     键
     * @param hashKey hash
     */
    public void delCacheHashValue(final String key, final String hashKey) {
        HashOperations hashOperations = redisTemplate.opsForHash();
        hashOperations.delete(key, hashKey);
    }


    /**
     * 获取基本对象数据
     *
     * @param key 键
     */
    public <T> T getCacheObject(final String key) {
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }
    
    public <T> T get(String key, Class<T> cls) {
        return gson.fromJson(gson.toJson(redisTemplate.opsForValue().get(key)),cls);
    }

    /**
     * 获取List数据
     *
     * @param key 键
     */
    public <T> List<T> getCacheList(final String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }
    
    public <T> T delCacheListFirst(final String key) {
    	ListOperations<String,T> operation = redisTemplate.opsForList();
        return operation.leftPop(key);
    }
    
    public <T> T delCacheListLast(final String key) {
    	ListOperations<String,T> operation = redisTemplate.opsForList();
        return operation.rightPop(key);
    }
    
    /**
     * //从左边删除第一个元素
        String s = redisTemplate.opsForList().leftPop("students");
        //从右边删除第一个元素
        String s1 = redisTemplate.opsForList().rightPop("students");

        //count > 0; 删除左边起第几个等于指定值的元素
        //count < 0; 删除右边起第几个等于指定值的元素
        //count = 0; 删除所有等于value的元素
        //删除左边起第二个wb
        redisTemplate.opsForList().remove("students",2,"wb");
     * @param <T>
     * @param key
     * @param value 类型必须匹配
     * @return
     */
    public <T> Long delCacheList(final String key, final T value) {
    	ListOperations<String,T> operation = redisTemplate.opsForList();
        return operation.remove(key, 1, value);
    }
    
    /**
     * get list size
     * @param key
     * @return
     */
    public long getCacheListSize(final String key) {
    	return redisTemplate.opsForList().size(key);
    }

    /**
     * 获取Set数据
     *
     * @param key 键
     */
    public <T> Set<T> getCacheSet(final String key) {
        return redisTemplate.opsForSet().members(key);
    }

    /**
     * 获取Map数据
     *
     * @param key 键
     */
    public <T> Map<String, T> getCacheMap(final String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * 获取Hash对象数据
     *
     * @param key     键
     * @param hashKey hash
     */
    public <T> T getCacheHashValue(final String key, final String hashKey) {
        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
        return opsForHash.get(key, hashKey);
    }

    /**
     * 获取多个Hash对象数据
     *
     * @param key      键
     * @param hashKeys hash数组
     */
    public <T> List<T> getMultiCacheHashValue(final String key, final Collection<Object> hashKeys) {
        return redisTemplate.opsForHash().multiGet(key, hashKeys);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     */
    public boolean exist(String key) {
        return redisTemplate.hasKey(key);
    }
    
    /**
     * 订阅/发布模式
     * @param <T>
     * @param key
     * @param data
     */
    public <T> void produce(final String key, final T data) {
        redisTemplate.convertAndSend(key, data);
    }
}
